#include <webx/menu.h>
#include <webx/route.h>
#include <dbentity/T_XG_USER.h>
#include <dbentity/T_XG_NOTE.h>
#include <dbentity/T_XG_CODE.h>
#include <dbentity/T_XG_DBETC.h>
#include <dbentity/T_XG_PARAM.h>

class CheckLogin : public webx::ProcessBase
{
protected:
	int process();
};

HTTP_WEBAPP(CheckLogin)

int CheckLogin::process()
{
	int res = XG_OK;
	int timeout = 1800;
	string sid = webx::GetSessionId(request);

	param_string(flag);

	if (flag == "U")
	{
		checkSession(sid);

		try
		{
			checkSystemRight();

			session->setTimeout(1800);
		}
		catch(Exception e)
		{
		}
	}
	else if (flag == "Q")
	{
		checkSession(sid);

		session->disable();
	}
	else if (flag == "C")
	{
		try
		{
			checkLogin(sid);

			json["user"] = user;
			json["dbid"] = this->dbid;
			json["name"] = session->get("NAME");
			json["language"] = session->get("LANGUAGE");
			json["grouplist"] = session->get("GROUPLIST");

			try
			{
				checkSystemRight();

				session->setTimeout(1800);
			}
			catch(Exception e)
			{
			}
		}
		catch(Exception e)
		{
			if (!session)
			{
				while (true)
				{
					sid = DateTime::GetBizId() + app->getSequence();
					sid = MD5GetEncodeString(sid.c_str(), sid.length(), true).val;

					session = webx::GetSession(sid);

					if (!session)
					{
						session = webx::GetSession(sid, timeout);

						break;
					}
				}

				webx::SetSessionId(response, sid);
			}

			res = XG_TIMEOUT;
		}
	}
	else
	{
		param_string(user);
		param_string(passwd);
	
		string sqlcmd;
		CT_XG_USER tab;
		sp<QueryResult> rs;
		sp<DBConnect> dbconn = webx::GetDBConnect();

		if (user.empty() || passwd.empty())
		{
			param_string(mail);
			param_string(code);

			stdx::tolower(mail);
			stdx::tolower(code);

			if (sid.empty()) return simpleResponse(XG_TIMEOUT);
			
			if (mail.empty() || code.empty() || mail.find('@') == string::npos) return simpleResponse(XG_PARAMERR);

			checkSession(sid);

			if (mail != session->get("MAIL")) return simpleResponse(XG_DATAERR);
			
			if (code != session->get("CODE")) return simpleResponse(XG_AUTHFAIL);
			
			string dbid;
			string name = mail.substr(0, mail.find('@'));

			user = mail;

			tab.init(dbconn);

			auto GetDataId = [](sp<DBConnect> dbconn){
				string dbid;
				string sqlcmd = "SELECT ID FROM T_XG_DBETC WHERE ENABLED>1 ORDER BY STRESS ASC LIMIT 1";

				if (dbconn->select(dbid, sqlcmd) < 0) stdx::Throw(XG_SYSERR, "system error");
				
				return dbid;
			};
			
			auto UpdateDataStress = [](sp<DBConnect> dbconn, const string& dbid){
				if (dbid.length() > 0) dbconn->execute("UPDATE T_XG_DBETC SET STRESS=STRESS+STEP WHERE ID=?", dbid);
			};

			stdx::format(sqlcmd, "MAIL='%s'", mail.c_str());

			if (!(rs = tab.find(sqlcmd)))
			{
				LogTrace(eIMP, "user[" + user + "] login failed");
				
				return simpleResponse(XG_SYSERR);
			}

			if (tab.next())
			{
				LogTrace(eIMP, "user[" + user + "][" + sid + "] login success");

				res = XG_OK;
			}
			else if ((dbid = GetDataId(dbconn)).empty())
			{
				res = XG_SYSERR;
			}
			else
			{
				LogTrace(eIMP, "user[" + user + "] does not exist");
				
				tab.dbid = dbid;
				tab.user = user;
				tab.name = name;
				tab.mail = mail;

				tab.level = "0";
				tab.passwd = "";
				tab.enabled = "1";
				tab.language = "CN";
				tab.grouplist = "normal";
				tab.statetime.update();
				
				if ((res = tab.insert()) >= 0)
				{
					LogTrace(eIMP, "create user[" + user + "] success");

					UpdateDataStress(dbconn, dbid);
					webx::InitNewUser(user);

					res = XG_OK;
				}
			}

			if (res > 0) json["user"] = tab.user.val();
		}
		else if (webx::IsFileName(user))
		{
			tab.init(dbconn);
			
			string mail = user;
			
			stdx::format(sqlcmd, "USER='%s' OR MAIL='%s'", user.c_str(), stdx::tolower(mail).c_str());
		
			if (!(rs = tab.find(sqlcmd)))
			{
				LogTrace(eIMP, "user[" + user + "] login failed");
				
				return simpleResponse(XG_SYSERR);
			}

			if (tab.next())
			{
				int times = 0;
				int maxnum = 5;
				int timeout = 600;
				sp<Session> session = webx::GetSession("LOGINLIMIT[" + tab.user.val() + "]", timeout);

				session->get("TIMES", times);

				if (times++ <= 0) times = 1;

				if (times > maxnum)
				{
					LogTrace(eIMP, "user[" + user + "] login frequently");

					session->setTimeout(timeout);

					json["timeout"] = timeout;

					res = XG_SYSBUSY;
				}
				else if (passwd == tab.passwd.val())
				{
					if (tab.enabled.val() < 1)
					{
						LogTrace(eIMP, "user[" + user + "] disabled");

						res = XG_NOTFOUND;
					}
					else
					{
						LogTrace(eIMP, "user[" + user + "] login success");

						res = XG_OK;
					}
				}
				else
				{
					LogTrace(eIMP, "user[" + user + "] login password error");

					session->set("TIMES", times);

					json["timeout"] = timeout;

					res = XG_AUTHFAIL;
				}

				json["times"] = maxnum - times;
			}
			else
			{
				LogTrace(eIMP, "user[" + user + "] does not exist");

				res = XG_NOTFOUND;
			}

			if (res > 0) json["user"] = tab.user.val();
		}
		else
		{
			res = XG_PARAMERR;
		}

		if (res == XG_OK)
		{
			timeout = 1800;

			try
			{
				checkSystemRight(tab.grouplist.val());
			}
			catch(Exception e)
			{
				string val = webx::GetParameter("LOGIN_TIMEOUT");
				
				if (val.empty())
				{
					timeout = 7 * 24 * 3600;
				}
				else
				{
					timeout = (int)(stdx::atof(val.c_str()) * 24 * 3600);
					
					if (timeout < 600) timeout = 600;
				}
			}

			try
			{
				checkSession(sid);
				
				session->disable();
			}
			catch(Exception e)
			{
			}

			while (true)
			{
				sid = DateTime::GetBizId() + app->getSequence() + tab.user.val() + tab.name.val() + tab.language.val() + tab.grouplist.val();
				sid = MD5GetEncodeString(sid.c_str(), sid.length(), true).val;

				session = webx::GetSession(sid);

				if (!session)
				{
					session = webx::GetSession(sid, timeout);

					break;
				}
			}

			session->set("GROUPLIST", tab.grouplist.val());
			session->set("LANGUAGE", tab.language.val());
			session->set("DBID", tab.dbid.val());
			session->set("USER", tab.user.val());
			session->set("NAME", tab.name.val());

			webx::SetSessionId(response, sid);

			timeout = 3600;

			while (true)
			{
				sid = DateTime::GetBizId() + stdx::str(rand());
				sid = MD5GetEncodeString(sid.c_str(), sid.length(), true).val;

				session = webx::GetLocaleSession("TOKEN[" + sid + "]");

				if (!session)
				{
					session = webx::GetLocaleSession("TOKEN[" + sid + "]", timeout);
					
					if (!session)
					{
						LogTrace(eERR, "create session failed");

						return simpleResponse(XG_SYSERR);
					}

					break;
				}
			}

			response->addCookie("token", sid, timeout);

			HttpDataNode data;
			data.setValue("token", sid);
			data.setValue("timeout", stdx::str(timeout));
			webx::Broadcast("createtoken", data.toString());
		}
	}

	json["code"] = res;
	out << json;
	
	return XG_OK;
}